package com.metaverse.backend.service;

import com.alibaba.fastjson.JSONObject;
import com.metaverse.backend.config.DouYinProperties;
import com.metaverse.backend.config.RedisCacheKey;
import com.metaverse.backend.domain.RoomLog;
import com.metaverse.backend.domain.User;
import com.metaverse.backend.douyin.PlayerDataDTO;
import com.metaverse.backend.douyin.RoomDataDTO;
import com.metaverse.backend.dto.GameInfoDTO;
import com.metaverse.backend.dto.RankItemDTO;
import com.metaverse.backend.dto.RankUserDTO;
import com.metaverse.backend.enums.GiftTypeEnum;
import com.metaverse.backend.enums.MsgTypeEnum;
import com.metaverse.backend.exception.BusinessException;
import com.metaverse.backend.repo.RoomLogRepo;
import com.metaverse.backend.utils.ApplicationContextUtil;
import com.metaverse.backend.utils.HttpUtils;
import com.metaverse.backend.utils.SnowflakeIdWorker;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 抖音接口服务
 *
 */
@Service
@AllArgsConstructor
@Slf4j
public class DouYinApiService {
    private HttpUtils httpUtils;
    private RedisTemplate<String, String> redisTemplate;

    private DouYinProperties douYinProperties;


    /**
     * 获取access_token
     * 正式请求地址 POST https://developer.toutiao.com/api/apps/v2/token
     * 沙盒请求地址 POST https://open-sandbox.douyin.com/api/apps/v2/token
     * appid string  小程序 ID
     * secret  string 小程序的 APP Secret，可以在开发者后台获取
     * grant_type string 获取 access_token 时值为 client_credential
     */
    private String getAccessToken() {
        JSONObject reqData = new JSONObject();
        reqData.put("appid", douYinProperties.getAppid());
        reqData.put("secret", douYinProperties.getSecret());
        reqData.put("grant_type", "client_credential");

        String fullUrl = "https://developer.toutiao.com/api/apps/v2/token";
        String resStr = null;
        try {
            resStr = httpUtils.doPostJson(fullUrl, reqData.toJSONString());
        } catch (IOException e) {
            log.error("接口网络问题，地址：{}, 参数：{}", fullUrl, reqData, e);
            throw new BusinessException("接口网络错误");
        }

        log.info("启动直播间getAccessToken，fullUrl：{}, 抖音返回结果{}", fullUrl, resStr);
        JSONObject jsonRes = JSONObject.parseObject(resStr);
        Integer errNo = jsonRes.getInteger("err_no");
        String errTips = jsonRes.getString("err_tips");
        if (errNo != 0) {
            throw new BusinessException(errTips + "[" + errNo + "]");
        }

        JSONObject data = jsonRes.getJSONObject("data");
        return data.getString("access_token");

    }


    /**
     * 请求接口
     *
     * @param reqData
     * @return
     */
    private JSONObject executeApi(String fullUrl, JSONObject reqData) {
        Map<String, String> headers = new HashMap<String, String>();
        String accessToken = getAccessTokenFromCache();
        headers.put("access-token", accessToken);
        headers.put("x-token", accessToken);
        headers.put("X-Token", accessToken);
        String resStr = null;
        try {
            resStr = httpUtils.doPostJson(fullUrl, reqData.toJSONString(), headers);
        } catch (IOException e) {
            log.error("接口网络问题，地址：{}, 参数：{},类型{}", fullUrl, reqData);
            throw new BusinessException("接口网络错误", e);
        }

        JSONObject jsonRes = JSONObject.parseObject(resStr);
        {
            Integer errNo = jsonRes.getInteger("err_no");
            String errMsg = jsonRes.getString("err_msg");
            if (errNo != null && errNo != 0) {
                throw new BusinessException(errMsg + "[" + errNo + "]");
            }
        }

        {
            Integer errcode = jsonRes.getInteger("errcode");
            String errmsg = jsonRes.getString("errmsg");
            if (errcode != null && errcode != 0) {
                throw new BusinessException(errmsg + "[" + errcode + "]");
            }
        }


        return jsonRes;
    }


    /**
     * 获取token
     *
     * @return
     */
    public String getAccessTokenFromCache() {
        String accessToken = redisTemplate.opsForValue().get(RedisCacheKey.ACCESS_TOKEN);
        if (StringUtils.isEmpty(accessToken)) {
            //默认初始化一次
            accessToken = getAccessToken();
            redisTemplate.opsForValue().set(RedisCacheKey.ACCESS_TOKEN, accessToken, 3600, TimeUnit.SECONDS);
        }

        return accessToken;
    }


    /**
     * 启动直播间数据推送，启动成功后，直播间数据才会同步推送给开发者服务器
     * 频率限制：单个 app_id 调用上限为 10 次/秒。
     * 请求地址 POST https://webcast.bytedance.com/api/live_data/task/start
     * <p>
     * msg_type类型
     * 评论：live_comment
     * 礼物：live_gift
     * 点赞：live_like"
     */
    private void startGame(String roomid, MsgTypeEnum msgTypeEnum) {

        JSONObject bodys = new JSONObject();
        bodys.put("roomid", roomid);
        bodys.put("appid", douYinProperties.getAppid());
        bodys.put("msg_type", msgTypeEnum.getDescription());

        String url = "https://webcast.bytedance.com/api/live_data/task/start";

        JSONObject jsonRes = executeApi(url, bodys);
        JSONObject data = jsonRes.getJSONObject("data");
        String taskId = data.getString("task_id");
        log.info("启动类型：{},任务ID:{}, 完整响应：{}", msgTypeEnum, taskId, jsonRes);

    }

    /**
     * 礼物置顶
     */
    private void topGift(String roomid) {

        String fullUrl = "https://webcast.bytedance.com/api/gift/top_gift";

        List<String> giftList = new ArrayList<>();
        GiftTypeEnum[] giftTypeEnums = GiftTypeEnum.values();
        for(GiftTypeEnum giftTypeEnum : giftTypeEnums){
            if(StringUtils.isNotBlank(giftTypeEnum.getId())){
                giftList.add(giftTypeEnum.getId());
            }
        }

        JSONObject bodys = new JSONObject();
        bodys.put("room_id", roomid);
        bodys.put("app_id", douYinProperties.getAppid());
        bodys.put("sec_gift_id_list", giftList);

        JSONObject jsonRes = executeApi(fullUrl, bodys);


    }


    /**
     * 启动直播间数据推送，启动成功后，直播间数据才会同步推送给开发者服务器
     * 频率限制：单个 app_id 调用上限为 10 次/秒。
     * 请求地址 POST https://webcast.bytedance.com/api/live_data/task/start
     * <p>
     * msg_type类型
     * 评论：live_comment
     * 礼物：live_gift
     * 点赞：live_like"
     */
    private void stopGame(String roomid, MsgTypeEnum msgTypeEnum) {
        JSONObject bodys = new JSONObject();
        bodys.put("roomid", roomid);
        bodys.put("appid", douYinProperties.getAppid());
        bodys.put("msg_type", msgTypeEnum.getDescription());

        String url = "https://webcast.bytedance.com/api/live_data/task/stop";

        JSONObject jsonRes = executeApi(url, bodys);
        JSONObject data = jsonRes.getJSONObject("data");
        String taskId = data.getString("task_id");
        log.info("停止类型：{},任务ID:{}, 完整响应：{}", msgTypeEnum, taskId, jsonRes);

    }


    /**
     * 获取房间信息
     *{
     *   "data": {
     *     "info": {
     *       "room_id": 7214015683695250235,
     *       "anchor_open_id": "_000oJIu6APhomK7KIBGqSYm5XYPxCJB_xxx",
     *       "avatar_url": "https://p11.douyinpic.com/aweme/720x720/aweme-avatar/tos-cn-avt-0015_973c31e8055f78a41d3f7de3def9821d.jpeg?from=3067671334",
     *       "nick_name": "xxx"
     *     }
     *   }
     * }
     * @param token
     * @return
     */
    public JSONObject getRoomInfo(String token){

        JSONObject bodys = new JSONObject();
        bodys.put("token", token);

        String url = "https://webcast.bytedance.com/api/webcastmate/info";

        JSONObject jsonRes = executeApi(url, bodys);
        JSONObject data = jsonRes.getJSONObject("data");

        return data;
    }

    /**
     * 上报游戏结果
     *
     * @return
     */
    public JSONObject reportGameInfo(String anchorOpenId, RoomDataDTO roomDataDTO, List<PlayerDataDTO> rankList){

//        //上报游戏数据
//        GameInfoDTO gameInfoDTO = new GameInfoDTO();
//        gameInfoDTO.setApp_id(douYinProperties.getAppid());
//        gameInfoDTO.setRoom_id(roomDataDTO.getRoomId());
//        gameInfoDTO.setRound_id(roomDataDTO.getRoundId());
//        gameInfoDTO.setAnchor_open_id(anchorOpenId);
//        gameInfoDTO.setStart_time(roomDataDTO.getStartTime());
//        gameInfoDTO.setEnd_time(roomDataDTO.getEndTime());
//        //超过一小时非正常
//        if((roomDataDTO.getEndTime() - roomDataDTO.getStartTime()) >= 3600 * 1000){
//            gameInfoDTO.setEnd_status(2);
//        }else{
//            gameInfoDTO.setEnd_status(1);
//        }
//
//        RankItemDTO victoryItem = new RankItemDTO();
//        victoryItem.setRank_users(new ArrayList<>());
//        victoryItem.setRank_result_comment("win");
//        RankItemDTO failItem = new RankItemDTO();
//        failItem.setRank_users(new ArrayList<>());
//        failItem.setRank_result_comment("fail");
//        rankList.forEach(item -> {
//            RankUserDTO rankUserDTO = new RankUserDTO();
//            rankUserDTO.setOpen_id(item.getSec_openid());
//            rankUserDTO.setRank(item.getRank());
//            rankUserDTO.setScores(item.getScore());
//            if(item.getRank()==1){
//                victoryItem.getRank_users().add(rankUserDTO);
//            }else{
//                failItem.getRank_users().add(rankUserDTO);
//            }
//        });
//        gameInfoDTO.setRank_lists(Arrays.asList(victoryItem,failItem));
//
//        String url = "https://webcast.bytedance.com/api/live_data/game/info";
//
//        //TODO 接口签名复杂,待完成...
//        log.info("上报数据内容：" + gameInfoDTO);
        return null;
    }




    /**
     * @param header  = {
     *                "x-nonce-str": "123456",
     *                "x-timestamp": "456789",
     *                "x-roomid":    "268",
     *                "x-msg-type":  "live_gift",
     *                }
     * @param bodyStr = "abc123你好"
     * @return PDcKhdlsrKEJif6uMKD2dw==
     * @jdk >= 1.8
     */
    public boolean signature(Map<String, String> header, String bodyStr, String signature, String secret) throws Exception {
        List<String> keyList = new ArrayList<>(4);
        header.forEach((key, val) -> keyList.add(key));
        Collections.sort(keyList, String::compareTo);

        List<String> kvList = new ArrayList<>(4);
        for (String key : keyList) {
            kvList.add(key + "=" + header.get(key));
        }
        String urlParams = String.join("&", kvList);
        String rawData = urlParams + bodyStr + secret;
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(rawData.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(md.digest()).equals(signature);
    }


    /**
     * 启动所有任务
     * @param roomId
     * @param count
     */
    public void tryStartAll(String roomId, int count){
        Exception lastError = null;
        for(int i = 0 ; i < count; i++){

            try {
                //没有局号就是新房间,需要启动抖音推送 礼物置顶
                startGame(roomId, MsgTypeEnum.LIVE_COMMENT);
                startGame(roomId, MsgTypeEnum.LIVE_GIFT);
                startGame(roomId, MsgTypeEnum.LIVE_LIKE);
//                topGift(roomId);//礼物置顶
                lastError = null;
                break;
            }catch(Exception err){
                log.error("任务启动失败，房间："+roomId+"， 序号：" + i , err);
                lastError = err;
            }

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                log.error("启动任务中断", e);
                break;
            }

        }

        if(lastError != null){
            //最后还是启动失败
            throw new RuntimeException("任务启动失败", lastError);
        }

    }



}
